home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Source / MacTech's Sprocket™ / SprocketGX / Lib / DialogUtils.cp < prev    next >
Encoding:
Text File  |  1994-10-17  |  9.4 KB  |  352 lines  |  [TEXT/MMCC]

  1. /*
  2.     File:        DialogUtils.cp
  3.  
  4.     Contains:    Auto-sized error alert mechanism,
  5.                 ModalFilterProcs which correctly handle events,
  6.                 and Standard “Close Document” dialogs. 
  7.  
  8.     Written by: Dave Falkenburg
  9.  
  10.     Copyright:    © 1993-94 by Dave Falkenburg, all rights reserved.
  11.  
  12.     Change History (most recent first):
  13.      
  14.  */
  15.  
  16. #include <Types.h>
  17. #include <Memory.h>
  18. #include <Quickdraw.h>
  19. #include <Fonts.h>
  20. #include <Resources.h>
  21. #include <Windows.h>
  22. #include <Dialogs.h>
  23. #include <TextUtils.h>
  24. #include <Threads.h>        //    For YieldToAnyThread()
  25. #include <StandardFile.h>    //    For ModalFilterYDProcPtr
  26. #include <SegLoad.h>
  27. #ifdef    __SC__
  28.     #include "StdFilterProc.h"
  29. #endif //    __SC__
  30. #include "AppLib.h"
  31.  
  32.  
  33. //    Some types which should probably be defined in <Dialogs.h>
  34. //    NOTE: These must be aligned on 2-byte boundaries
  35. #if defined(powerc) || defined (__powerc)
  36. #pragma options align=mac68k
  37. #endif
  38.  
  39. struct DialogItem
  40. {
  41.     long    usedByDialogManager;
  42.     Rect    boundsRect;
  43.     char    type;
  44.     char    length;
  45. };
  46.     
  47. struct DialogItemList            //    a.k.a. a 'DITL'
  48. {
  49.     short        count;
  50.     DialogItem    firstItem[1];
  51. };
  52.  
  53. //    Restore default alignment
  54. #if defined(powerc) || defined(__powerc)
  55. #pragma options align=reset
  56. #endif
  57.  
  58. typedef    DialogItem        *DialogItemPtr;
  59. typedef    DialogItemList    **DialogItemListHandle;
  60. typedef    DialogTemplate    **DialogTemplateHandle;
  61.  
  62.  
  63. //    private function Prototypes
  64.  
  65. static    pascal Boolean    StandardDialogFilterProc(DialogPtr theDialog, EventRecord * anEvent, short * itemHit);
  66. static    pascal Boolean    StandardDialogFilterYDProc(DialogPtr theDialog, EventRecord * anEvent, short * itemHit, void * yourData);
  67. static    pascal Boolean    StandardCloseDialogFilterProc(DialogPtr theDialog, EventRecord * anEvent, short * itemHit);
  68. static    Boolean            FilterProcCommon(DialogPtr theDialog, EventRecord * anEvent, short * itemHit);
  69.  
  70.  
  71. ///////////////////////////////////////////////////////////
  72. //
  73. //    StandardAlert
  74. //
  75. //    An alternative to Alert() which uses the extended
  76. //    Dialog Manager capabilities.
  77. //
  78. //    I’m not sure we really need this call, but it seems
  79. //    to do the trick just fine.
  80.  
  81. short StandardAlert(short dlogID,
  82.                 short defaultItem,                /* = ok */
  83.                 short cancelItem,                /* = 0 */
  84.                 ModalFilterUPP customFilterProc    /* = nil */)
  85. {
  86.     DialogPtr        theDialog;
  87.     short            itemHit = 0;
  88.     ModalFilterUPP    filterToUse;
  89.     
  90.     HiliteWindowsForModalDialog(false);
  91.  
  92.     theDialog = GetNewDialog(dlogID,nil,(WindowPtr) -1);
  93.     if (defaultItem)
  94.         SetDialogDefaultItem(theDialog,defaultItem);
  95.     if (cancelItem)
  96.         SetDialogCancelItem(theDialog,cancelItem);
  97.  
  98.     if (customFilterProc)
  99.         filterToUse = customFilterProc;
  100.     else
  101.         filterToUse = StandardDialogFilter;
  102.  
  103.     do
  104.         ModalDialog(filterToUse,&itemHit);
  105.     while (itemHit == 0);
  106.     
  107.     DisposeDialog(theDialog);
  108.  
  109.     HiliteWindowsForModalDialog(true);
  110.  
  111.     return itemHit;
  112. }
  113.  
  114. ///////////////////////////////////////////////////////////
  115. //
  116. //    ErrorAlert
  117. //
  118. //    A nice error reporting routine which presents an
  119. //    auto-sized alert box containing the supplied text.
  120. //
  121. //    NOTE:    This routine ASSUMES the following 'DITL'
  122. //            structure:
  123. //
  124. //            item #1 : an “OK” button
  125. //            item #2 : a static text item, somewhere above #1
  126. //
  127. //    NOTE:    We probably need to worry more about low
  128. //            memory conditions-- this can probably
  129. //            be handled by a custom GrowZoneProc and
  130. //            reserve memory area large enough to hold
  131. //            all the space we’d need.
  132. //
  133. void ErrorAlert(short stringList,short whichString)
  134. {
  135.     Str255                    errorString;
  136.     GrafPtr                    windowMgrPort;
  137.     short                    oldFont;
  138.     DialogTemplateHandle    errorDialogTemplate;
  139.     DialogItemListHandle    errorDialogItems;
  140.     TEHandle                aTEHandle;
  141.     Rect                    textRect;
  142.     short                    textHeight;
  143.     short                    additionalSpaceNeeded;
  144.     DialogItemPtr            okButtonItem,errorTextItem;
  145.     const StringPtr            nullStr = (StringPtr) "\p";
  146.  
  147.     GetIndString(errorString,stringList,whichString);
  148.     
  149.     errorDialogTemplate = (DialogTemplateHandle) Get1Resource('DLOG',kErrorAlertID);
  150.     HLock((Handle) errorDialogTemplate);
  151.     
  152.     errorDialogItems = (DialogItemListHandle) Get1Resource('DITL',(**errorDialogTemplate).itemsID);
  153.     HLock((Handle) errorDialogItems);
  154.     
  155.     //    Find the dialog items
  156.     
  157.     okButtonItem = (**errorDialogItems).firstItem;
  158.     errorTextItem = (DialogItemPtr) ((Ptr) okButtonItem + sizeof(DialogItem) + okButtonItem->length);
  159.     
  160.     GetWMgrPort(&windowMgrPort);
  161.     {
  162.         CSavePort  aSavePort(windowMgrPort);
  163.  
  164.         oldFont = qd.thePort->txFont;
  165.         TextFont(systemFont);
  166.  
  167.         aTEHandle = TENew(&textRect,&textRect);
  168.         TESetText(&errorString[1],errorString[0],aTEHandle);
  169.         textHeight = (*aTEHandle)->lineHeight * (*aTEHandle)->nLines;
  170.         TEDispose(aTEHandle);
  171.  
  172.         additionalSpaceNeeded = textHeight - (errorTextItem->boundsRect.bottom
  173.                             - errorTextItem->boundsRect.top);
  174.  
  175.         if (additionalSpaceNeeded > 0)
  176.         {
  177.             (**errorDialogTemplate).boundsRect.bottom += additionalSpaceNeeded;
  178.             errorTextItem->boundsRect.bottom += additionalSpaceNeeded;
  179.             OffsetRect(&okButtonItem->boundsRect,0,additionalSpaceNeeded);
  180.         }
  181.             
  182.         TextFont(oldFont);
  183.     }
  184.     
  185.     InitCursor();
  186.     ParamText(errorString,nullStr,nullStr,nullStr);
  187.  
  188.     (void) StandardAlert(kErrorAlertID);
  189.  
  190.     ReleaseResource((Handle) errorDialogTemplate);
  191.     ReleaseResource((Handle) errorDialogItems);
  192. }
  193.  
  194.  
  195. ///////////////////////////////////////////////////////////
  196. //
  197. //    FatalErrorAlert
  198. //
  199. //    A companion to ErrorAlert which also kills the process.
  200. //
  201.  
  202. void
  203. FatalErrorAlert(short stringList,short whichString)
  204. {
  205.     ErrorAlert(stringList,whichString);
  206.     ExitToShell();
  207. }
  208.  
  209.  
  210. ///////////////////////////////////////////////////////////
  211. //
  212. //    StandardDialogFilter and StandardDialogFilterYD
  213. //
  214. //    These function takes care of routing events not meant
  215. //    for the dialog window to other parts of the application.
  216. //
  217. //    Use them as an alternative to passing a NIL ModalFilterProc
  218. //    to ModalDialog() and CustomGet(Put)File. Unlike the default
  219. //    filter, these routines properly processes update events
  220. //    to keep background processes running.
  221. //
  222. //    The Thread Manager, if present, is also called to yield
  223. //    control to other cooperative threads within the process.
  224. //
  225. //    Because of pascal calling conventions we need two separate
  226. //    routines, but this is minimized by sharing implementation
  227. //    in FilterProcCommon.
  228. //
  229.  
  230. ModalFilterUPP    StandardDialogFilter
  231. = NewModalFilterProc(StandardDialogFilterProc);
  232.  
  233. ModalFilterYDUPP    StandardDialogFilterYD
  234. = NewModalFilterYDProc(StandardDialogFilterYDProc);
  235.  
  236. ModalFilterUPP    StandardCloseDialogFilter
  237. = NewModalFilterProc(StandardCloseDialogFilterProc);
  238.  
  239. pascal Boolean StandardDialogFilterProc(DialogPtr theDialog, EventRecord* anEvent, short* itemHit)
  240.     {
  241.     //    Call through common code to check for events we’d like to handle.
  242.     //    If that is unsuccessful, call through the System 7 StdFilterProc
  243.     //    to handle CR, “CMD-.” & ESC in an international-friendly manner.
  244.  
  245.     if (FilterProcCommon(theDialog, anEvent, itemHit))
  246.         return true;
  247.     else
  248.         return (StdFilterProc(theDialog, anEvent, itemHit));
  249.     }
  250.  
  251.  
  252. pascal Boolean StandardDialogFilterYDProc(DialogPtr theDialog, EventRecord* anEvent, short* itemHit, void * /*unusedData*/)
  253. {
  254.     //    We don’t call through to StdFilterProc since the
  255.     //    Standard File Package already does everything we need.
  256.  
  257.     return FilterProcCommon(theDialog, anEvent, itemHit);
  258. }
  259.  
  260. void PseudoClickInDialogItem(DialogPtr theDialog, short itemToClick)
  261. {
  262.     Handle    itemHandle;
  263.     Rect    itemBox;
  264.     long    finalTicks;
  265.     short    itemType;
  266.     
  267.     GetDialogItem(theDialog,itemToClick,&itemType,&itemHandle,&itemBox);
  268.  
  269.     HiliteControl((ControlHandle) itemHandle,inButton);
  270.     Delay(8,&finalTicks);
  271.     HiliteControl((ControlHandle) itemHandle,0);
  272. }
  273.  
  274. pascal Boolean StandardCloseDialogFilterProc(DialogPtr theDialog, EventRecord* anEvent, short* itemHit)
  275. {
  276.     if ((anEvent->what == keyDown))
  277.         {
  278.         char    c = anEvent->message & charCodeMask;
  279.         
  280.         if ((c == 'd') || (c == 'D'))                //    NOT INTERNATIONAL FRIENDLY!!!
  281.             {
  282.             *itemHit = kDontSaveDocument;
  283.             PseudoClickInDialogItem(theDialog,kDontSaveDocument);
  284.             return true;
  285.             }
  286.         }
  287.  
  288.     //    Return through the common code above so that default item processing can happen
  289.     return StandardDialogFilterProc(theDialog, anEvent, itemHit);
  290. }
  291.  
  292. Boolean FilterProcCommon(DialogPtr theDialog, EventRecord * anEvent, short * /* itemHit */)
  293. {
  294.     switch (anEvent->what)
  295.     {
  296.         case updateEvt:
  297.         case activateEvt:
  298.             //     Update or activate for the dialog window?
  299.             if (theDialog == (DialogPtr) anEvent->message)
  300.                 break;
  301.  
  302.             //    no, fall through to HandleEvent            
  303.             
  304.         case diskEvt:
  305.             HandleEvent(anEvent);
  306.             return(false);
  307.  
  308.         default:
  309.             break;        
  310.         }
  311.  
  312.     if (gHasThreadManager)        //    If we have threads, let them run!
  313.         YieldToAnyThread();
  314.  
  315.     return false;                //    We didn’t handle the event
  316. }
  317.  
  318. //////////////////////////////////////////////////////////////////
  319. //
  320. //    StandardCloseDocument
  321. //
  322. //    Provides the standard human interface for closing a document
  323. //
  324. //    NOTE: When we make TDocument class, this will become a method
  325. //          and probably won’t need any parameters.
  326. //
  327. //    NOTE:    StandardCloseResult matches the dialog items for 
  328.  
  329. StandardCloseResult StandardCloseDocument(const StringPtr documentType, StringPtr documentName,
  330.                       Boolean hasNewEditions, Boolean quitting)
  331. {
  332.     short        whichAlert;
  333.     short        whichString;
  334.     StringPtr    nullStr = (StringPtr) "\p";
  335.     Str255        reasonForClosingStr;
  336.  
  337.     if (hasNewEditions)
  338.         whichAlert = kStandardCloseWithNewPubsAlertID;
  339.     else
  340.         whichAlert = kStandardCloseAlertID;
  341.     
  342.     if (quitting)
  343.         whichString = kQuittingStr;
  344.     else
  345.         whichString = kClosingStr;
  346.  
  347.     GetIndString(reasonForClosingStr,kStandardCloseStrings,whichString);
  348.     ParamText(documentType,documentName,reasonForClosingStr,nullStr);
  349.     
  350.     return ((StandardCloseResult) StandardAlert(whichAlert,kSaveDocument,kCancelSaveDocument,StandardCloseDialogFilter));
  351. }
  352.